$(function(){
	var SpdUI = window.SpdUI || {};
	window.SpdUI = SpdUI;
	
	SpdUI.contextPath = $('#hiddenContextPath').val();
	SpdUI.url = {
		login: SpdUI.contextPath + '/admin/login.do',
		logout: SpdUI.contextPath + '/admin/logout.do'
	};
	
	SpdUI.result = {
		SUCCESS: '0',
		isSuccess: function(json) {
			if(json && json.code === SpdUI.result.SUCCESS){
				return true;
			}else{
				return false;
			}
		},
		getData: function(json) {
			return json ? json.data : null;
		}
	};
	SpdUI.isResultSuccess = SpdUI.result.isSuccess;
	SpdUI.getResultData = SpdUI.result.getData();
	
	SpdUI.isString = function(obj){
		return Object.prototype.toString.call(obj) === '[object String]';
	};
	
	SpdUI.isNotString = function(obj){
		return Object.prototype.toString.call(obj) !== '[object String]';
	};
	
	SpdUI.fnCodeFactory = {
		fnCodes: {},
		run: function(code, data){
			if(SpdUI.isNotString(code)){
				return;
			}
			
			code = $.trim(code);
			if(code === '' || !SpdUI.fnCodeFactory.fnCodes.hasOwnProperty(code)){
				return;
			}
			
			SpdUI.fnCodeFactory.fnCodes[code](data);
		},
		add: function(code, fn){
			if(SpdUI.isString(code) && $.isFunction(fn)){
				code = $.trim(code);
				if(code !== ''){
					SpdUI.fnCodeFactory.fnCodes[code] = fn;
				}
			}
		}
	};
	SpdUI.addFnCode = SpdUI.fnCodeFactory.add;
	SpdUI.runFnCode = SpdUI.fnCodeFactory.run;
	
	SpdUI.encodeBase64 = function(str) {
		if(SpdUI.isString(str)){
			return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str));
		}else{
			return '';
		}
		
		//return Base64.encode(str);
	};
	
	SpdUI.decodeBase64 = function(str) {
		if(SpdUI.isString(str)){
			return CryptoJS.enc.Base64.parse(str).toString(CryptoJS.enc.Utf8);
		}else{
			return '';
		}
	};
	

	SpdUI.uuid = function() {
		var i, r, uuid = [], chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');

		// rfc4122, version 4 form
		// rfc4122 requires these characters
		uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
		uuid[14] = '4';

		// Fill in random data. At i==19 set the high bits of clock sequence as
		// per rfc4122, sec. 4.1.5
		for (i = 0; i < 36; i++) {
			if (!uuid[i]) {
				r = 0 | Math.random() * 16;
				uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
			}
		}

		return uuid.join('');
	};
	
	SpdUI.encryptAES = function(str) {
		if(SpdUI.isNotString(str)){
			str = SpdUI.toJSONString(str);
		}
		
		var id = SpdUI.uuid().toLowerCase().replace(/-/g, ''),
			encrypt = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(str), CryptoJS.enc.Utf8.parse(id.substring(0, 16)), {
				iv: CryptoJS.enc.Utf8.parse(id.substring(16)),
				mode: CryptoJS.mode.CBC,
			    padding: CryptoJS.pad.Pkcs7
			});
		
		return SpdUI.encodeBase64(id + encrypt.toString(CryptoJS.format.Hex));
	};
	
	SpdUI.decryptAES = function(str) {
		if(SpdUI.isNotString(str)){
			return;
		}
		
		var word = SpdUI.decodeBase64(str),
			id = word.substring(0, 32),
			data = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(word.substring(32)));
		return CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(id.substring(0, 16)), {
			iv: CryptoJS.enc.Utf8.parse(id.substring(16)),
			mode: CryptoJS.mode.CBC,
			padding: CryptoJS.pad.Pkcs7
		}).toString(CryptoJS.enc.Utf8);
	};
	
	SpdUI.toJSONString = function(obj) {
		return JSON.stringify(obj);
	};
	
	SpdUI.parseJSON = function(str) {
		return $.parseJSON(str);
	};
	
	/**
	 * 初始化
	 */
	SpdUI.initFrame = function(){
		var height = $(window).height() - 50;
		$('#mainWrapper').height(height);
		$('#mainTabs').height(height);
		$('#mainSidebar').height(height);
		$('#mainTabs>.tab-content').height(height - 48);
		
		$('#mainTabs').addtabs({
			contextmenu: true,
			monitor: 'mainSidebar',
			iframeHeight: '100%'
		});
		
		$('#mainTabHome>iframe').height('100%');
		
		$('#mainSidebarMenu').on('click', 'a[data-id]', function(){
			var $this = $(this),
				name = $this.data('name'),
				code = $this.data('code'),
				type = +$this.data('type'),
				url = $this.data('url');
			
			if(type === 1){
				// 新增tab
				Addtabs.add({
		            id: code,
		            title: name,
		            url: url
		        });
				
				return false;
			}else if(type === 2){
				// 执行功能
				SpdUI.runFnCode(code, {
					name: name,
					code: code,
					type: type,
					url: url,
					el: $this
				});
				return false;
			}
		});
	};
	
	$.validator.config({
		rules: {
	        mobile: [/^1[3|4|5|7|8][0-9]{9}$/, '请填写有效的手机号'],
	        email: [/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, '请填写正确的邮箱'],
	        chinese: [/^[\u0391-\uFFE5]+$/, '请填写中文字符']
	    }
	});	    
	
	$.validator.setTheme('spdui', {
        invalidClass: 'has-error',
        bindClassTo: '.spd-validate',
        formClass: 'n-yellow n-spdui',
        msgClass: 'n-right'
    });	
	
	SpdUI.formValidator = function(form, fields, msgPosition){
		var $form = $(form);
		if(form === undefined || form === null || $form.length === 0){
			return null;
		}
		
		var validator = $form.data('validator');
		if(validator){
			return validator;
		}
		
		if(!$.isPlainObject(fields)){
			return null;
		}
		
		var options = {
			timely: 3,
			theme: 'spdui',
			fields: fields
		};
		
		if(msgPosition !== undefined && Object.prototype.toString.call(msgPosition) === '[object String]'){
			options.msgClass = 'n-' + msgPosition;
		}
		
		return $form.validator(options);
	};
	
	SpdUI.cleanUpValidator = function(form){
		if(form === undefined || form === null){
			return;
		}
		
		var $form = $(form);
		if($form.length === 0){
			return;
		}
		
		$form.validator('cleanUp');
	};
	
	SpdUI.isValid = function(form, callback){
		var $form = $(form);
		if(form === undefined || form === null || $form.length === 0){
			return;
		}
		
		if($.isFunction(callback)){
			$form.isValid(callback);
		}else{
			return $form.isValid();
		}
	};
	
	/**
	 * 获取表单的值，返回json对象。
	 * @param form 表单元素、表单id、表单jQuery对象
	 */
	SpdUI.formToObject = function(form){
		var obj = {}, $form = $(form);
		if($form.length === 0){
			return obj;
		}
		
		var arr = $form.serializeArray();
		$.each(arr, function(i, v){
			var old = obj[v.name];
			if(old === undefined){
				obj[v.name] = v.value;
			}else if($.isArray(old)){
				obj[v.name].push(v.value);
			}else{
				obj[v.name] = [old, v.value];
			}
		});
		
		return obj;
	};
	
	// 别名
	SpdUI.formToJSON = SpdUI.formToObject;
	
	/**
	 * 把JSON对象内容填到Form中
	 * @param form   表单元素、表单id、表单jQuery对象
	 * @param object json对象
	 */
	SpdUI.objectToForm = function(form, object){
		var $form = $(form);
		if(!object || $form.length === 0){
			return;
		}
		
		$form.find('input[name]').each(function(){
			var elVal, $this = $(this), type = $this.attr('type').toLowerCase(), attrName = $.trim($this.attr('name')), objVal = object[attrName];
			if(attrName === '' || objVal === undefined || objVal === null){
				return;
			}
			
			if(type === 'checkbox' || type === 'radio'){
				elVal = $this.val();
				if($.isArray(objVal)){
					$.each(objVal, function(i, v){
						$this.prop('checked', elVal === v);
					});
				}else{
					$this.prop('checked', elVal === objVal);
				}
			}else{
				$this.val(objVal);
			}
		});
		
		$form.find('select[name],textarea[name]').each(function(){
			var value, $this = $(this), attrName = $.trim($this.attr('name')), value = object[attrName];
			if(attrName === '' || value === undefined || value === null){
				return;
			}
			
			$this.val(value);
		});
	};
	
	// 别名
	SpdUI.jsonToForm = SpdUI.objectToForm;
	
	/**
	 * confirm对话框
	 * @param message 对话框内容
	 * @param fnYes 回调函数，点击确定时触发。
	 * @param fnNo  回调函数，点击取消时触发。
	 */
	SpdUI.confirm = function(message, fnYes, fnNo){
		BootstrapDialog.show({
			title: '提示',
			message: message,
			buttons: [{
				label: '确定',
				cssClass: 'btn-primary',
				action: function(dialog) {
					if(fnYes && $.isFunction(fnYes)){
						fnYes();
					}
					
					dialog.close();
				}
			}, {
				label: '取消',
				cssClass: 'btn-default',
				action: function(dialog) {
					if(fnNo && $.isFunction(fnNo)){
						fnNo();
					}
					dialog.close();
				}
			}]
		});
	};
	
	/**
	 * alert对话框
	 * @param message 对话框内容
	 * @param callback 回调函数
	 */
	SpdUI.alert = function(message, callback){
		BootstrapDialog.show({
			title: '提示',
			message: message,
			buttons: [{
				label: '关闭',
				cssClass: 'btn-default',
				action: function(dialog) {
					if(callback && $.isFunction(callback)){
						callback();
					}
					dialog.close();
				}
			}]
		});
	};
	
	/**
	 * 获取dialog
	 * @param el html元素、id、jQuery对象
	 */
	SpdUI.getDialog = function(el){
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		return $el.data('spduiDialog');
	};
	
	/**
	 * 显示dialog
	 * @param el html元素、id、jQuery对象
	 * @param dialogData dialog绑定的数据
	 */
	SpdUI.openDialog = function(el, dialogData){
		var dialog = SpdUI.getDialog(el);
		
		if(dialog){
			var data = {}, odata = dialog.getData('dialogData');
			if($.isPlainObject(odata)){
				data = $.extend(data, odata);
			}
			
			if($.isPlainObject(dialogData)){
				data = $.extend(data, dialogData);
			}
			
			dialog.setData('dialogData', data);
			dialog.open();
		}
	};
	
	/**
	 * 显示form dialog
	 * @param el html元素、id、jQuery对象
	 * @param formData 表单数据
	 * @param dialogData dialog绑定的数据
	 */
	SpdUI.openFormDialog = function(el, formData, dialogData){
		var dialog = SpdUI.getDialog(el);
		
		if(dialog){
			var data = {}, odata = dialog.getData('dialogData');
			if($.isPlainObject(odata)){
				data = $.extend(data, odata);
			}
			
			if($.isPlainObject(dialogData)){
				data = $.extend(data, dialogData);
			}
			
			dialog.setData('dialogData', data);
			dialog.setData('formData', formData);
			dialog.open();
		}
	};
	
	/**
	 * 创建表单窗口
	 * @param form 表单元素、表单id、表单jQuery对象
	 * @param options 参数	 
	 */
	SpdUI.formDialog = function(form, options){
		var dialog, dataAttr = 'spduiDialog', $form = $(form);
		if(form === null || form === undefined || $form.length === 0){
			return;
		}
		
		dialog = $form.data(dataAttr);
		if(dialog){
			if(options){
				options.formData && dialog.setData('formData', options.formData);
				options.dialogData && dialog.setData('dialogData', options.dialogData);
			}
			return dialog;
		}
		
		options = $.extend({
			title: '窗口',
			submitLabel: '确定',
			cancelLabel: '取消',
			size: BootstrapDialog.SIZE_NORMAL,
			closable: false,
			autodestroy: false,
			autoShow: false,
			buttons: []
		}, options);
		
		/*
		options = {
			title: '窗口',
			formData: {
				name: name
			},
			dialogData: {},
			validate: {},
			buttons: [],
			autoShow: false,
			onsubmit: function(form, formData, dialog, dialaogData){				
			},
			oncancel: function(form, formData, dialog, dialaogData){				
			},
			oncreate: function(form, formData, dialog, dialaogData){			
			},
			onshow: function(form, formData, dialog, dialaogData){			
			},
			onhide: function(form, formData, dialog, dialaogData){
			}
		}
		*/
		
		if(options.buttons.length > 0){
			$.each(options.buttons, function(i, button){
				var fnact = button.action;
				button.action = function(dialog){
					var dialogData = dialog.getData('dialogData'),
						$form = dialog.getData('dialogBody'),
						dialogBody = dialog.getData('dialogBody');
					fnact($form, SpdUI.formToObject($form), dialog, dialogData);
				};
			});
		}
		
		options.buttons.push({
			label: options.submitLabel,
			cssClass: 'btn-primary',
			action: function(dialogRef){
				var $form = dialogRef.getData('dialogBody'),
					options = dialogRef.getData('dialogOptions');
				
				if(options.validate){
					SpdUI.isValid($form, function(){
						if(options.onsubmit && $.isFunction(options.onsubmit)){
							options.onsubmit($form, SpdUI.formToObject($form), dialogRef, dialogRef.getData('dialogData'));
						}
					});
				}else{
					if(options.onsubmit && $.isFunction(options.onsubmit)){
						options.onsubmit($form, SpdUI.formToObject($form), dialogRef, dialogRef.getData('dialogData'));
					}
				}
			}
		});
		
		options.buttons.push({
			label: options.cancelLabel,
			cssClass: 'btn-default',
			action: function(dialogRef){
				var dialogData = dialogRef.getData('dialogData'),
					options = dialogRef.getData('dialogOptions'),
					$form = dialogRef.getData('dialogBody'),
					result = true;
					
				if(options.oncancel && $.isFunction(options.oncancel)){
					result = options.oncancel($form, SpdUI.formToObject($form), dialogRef, dialogData);
				}
				
				if(result !== false){
					dialogRef.close();
				}
			}
		});
		
		dialog = new BootstrapDialog({
			title: options.title,
			closable: options.closable,
			autodestroy: options.autodestroy,
			message: $form,
			size: options.size,
			data: {
				dialogOptions: options,
				dialogBody: $form,
				formData: options.formData,
				dialogData: options.dialogData
			},
			buttons: options.buttons,
			onshow: function(dialogRef){
				var formData = dialogRef.getData('formData'),
					dialogData = dialogRef.getData('dialogData'),
					options = dialogRef.getData('dialogOptions'),
					$form = dialogRef.getData('dialogBody'),
					hasCreated = dialogRef.getData('hasCreated');
					
				$form.show();
				
				if(!hasCreated){
					setTimeout(function(){
						options.validate && SpdUI.formValidator($form, options.validate);
						
						if(options.oncreate && $.isFunction(options.oncreate)){
							options.oncreate($form, formData, dialogRef, dialogData);
						}
						
						dialogRef.setData('hasCreated', true);
					}, 200);
				}
				
				setTimeout(function(){
					formData && SpdUI.objectToForm($form, formData);
					
					if(options.onshow && $.isFunction(options.onshow)){
						options.onshow($form, formData, dialogRef, dialogData);
					}
				}, 300);
			},
			onhide: function(dialogRef){
				var dialogData = dialogRef.getData('dialogData'),
					options = dialogRef.getData('dialogOptions'),
					$form = dialogRef.getData('dialogBody'),
					formData = SpdUI.formToObject($form);
				
				dialogRef.setData('formData', null);
				
				if(options.onhide && $.isFunction(options.onhide)){
					options.onhide($form, formData, dialogRef, dialogData);
				}
				
				if(options.validate && $.isPlainObject(options.validate)){
					SpdUI.cleanUpValidator($form);
				}
				
				$form.get(0).reset();
			}
		});
		
		$form.data(dataAttr, dialog);
		
		if(options.autoShow === true){
			dialog.open();
		}
		
		return dialog;
	};
	
	/**
	 * 创建窗口
	 * @param dialogBody 窗口内容元素、id、jQuery对象
	 * @param options 参数	 
	 */
	SpdUI.dialog = function(dialogBody, options){
		var dialog, dataAttr = 'spduiDialog', $dialogBody = $(dialogBody);
		if(dialogBody === null || dialogBody === undefined || $dialogBody.length === 0){
			return;
		}
		
		dialog = $dialogBody.data(dataAttr);
		if(dialog){
			if(options && options.dialogData){
				dialog.setData('dialogData', options.dialogData);
			}
			return dialog;
		}
		
		options = $.extend({
			title: '窗口',
			closeLabel: '关闭',
			size: BootstrapDialog.SIZE_NORMAL,
			closable: false,
			autodestroy: false,
			autoShow: false,
			buttons: []
		}, options);
		
		/*
		options = {
			title: '窗口',
			autoShow: false,
			dialogData: {
				name: name
			},
			buttons: [],
			oncreate: function(dialog, dialogData, dialogBody){
			},
			onclose: function(dialog, dialogData, dialogBody){
			},
			onshow: function(dialog, dialogData, dialogBody){
			},
			onhide: function(dialog, dialogData, dialogBody){
			}
		}
		*/
		
		if(options.buttons.length > 0){
			$.each(options.buttons, function(i, button){
				var fnact = button.action;
				button.action = function(dialogRef){
					var dialogData = dialogRef.getData('dialogData'),
						dialogBody = dialogRef.getData('dialogBody');
					fnact(dialogRef, dialogData, dialogBody);
				};
			});
		}
		
		options.buttons.push({
			label: options.closeLabel,
			cssClass: 'btn-default',
			action: function(dialogRef){
				var dialogData = dialogRef.getData('dialogData'),
					dialogBody = dialogRef.getData('dialogBody'),
					options = dialogRef.getData('dialogOptions'),
					result = true;
					
				if(options.onclose && $.isFunction(options.onclose)){
					result = options.onclose(dialogRef, dialogData, dialogBody);
				}
				
				if(result !== false){
					dialogRef.close();
				}
			}
		});
		
		dialog = new BootstrapDialog({
			title: options.title,
			closable: options.closable,
			autodestroy: options.autodestroy,
			message: $dialogBody,
			size: options.size,
			data: {
				dialogOptions: options,
				dialogBody: $dialogBody,
				dialogData: options.dialogData
			},
			buttons: options.buttons,
			onshow: function(dialogRef){
				var dialogData = dialogRef.getData('dialogData'),
					dialogBody = dialogRef.getData('dialogBody'),
					dialogOptions = dialogRef.getData('dialogOptions'),
					hasCreated = dialogRef.getData('hasCreated');
					
				dialogBody.show();
				
				if(!hasCreated){
					if(dialogOptions.oncreate && $.isFunction(dialogOptions.oncreate)){
						setTimeout(function(){
							dialogOptions.oncreate(dialogRef, dialogData, dialogBody);							
						}, 200);
					}
					dialogRef.setData('hasCreated', true);
				}
				
				if(dialogOptions.onshow && $.isFunction(dialogOptions.onshow)){
					setTimeout(function() {
						dialogOptions.onshow(dialogRef, dialogData, dialogBody);
					}, 300);
				}
			},
			onhide: function(dialogRef){
				var dialogData = dialogRef.getData('dialogData'),
					dialogBody = dialogRef.getData('dialogBody'),
					dialogOptions = dialogRef.getData('dialogOptions');
				
				if(dialogOptions.onhide && $.isFunction(dialogOptions.onhide)){
					dialogOptions.onhide(dialogRef, dialogData, dialogBody);
				}
			}
		});
		
		$dialogBody.data(dataAttr, dialog);
		
		if(options.autoShow === true){
			dialog.open();
		}
		
		return dialog;
	};
	
	/**
	 * 创建时间日期选择器
	 * @param element html元素、id、jQuery对象
	 * @param options 参数
	 */
	SpdUI.daterangepicker = function(element, options){
		options = $.extend({
			autoUpdateInput: false,
			timePicker24Hour: true,
			timePickerSeconds: true,
			timePicker: true
		}, options);
		
		options.locale = $.extend({
			format: 'YYYY-MM-DD HH:mm:ss',
			separator: ' 到 ',
			applyLabel: '确定',
			cancelLabel: '清空',			
			fromLabel: '从',
			toLabel: '到',
			customRangeLabel: '自定义'
		}, options.locale);
		
		var $element = $(element),
			startId = options.startId || $(element).data('startId'),
			endId = options.endId || $(element).data('endId');
			
		var picker = $element.daterangepicker(options).on('apply.daterangepicker', function(event, picker){
			var $this = $(this), pattern = options.locale.format, singleDatePicker = options.singleDatePicker;
			
			if(singleDatePicker === true) {
				$this.val(picker.startDate.format(pattern));
			}else{
				$this.val(picker.startDate.format(pattern) + ' 到 ' + picker.endDate.format(pattern));
			}
			
			var startDateId = options.startDateId || $this.data('startDateId'),
				endDateId = options.endDateId || $this.data('endDateId');
				
			if(startDateId){
				$(startDateId).val(picker.startDate.format(pattern));
			}
			
			if(endDateId){
				$(endDateId).val(picker.endDate.format(pattern));
			}
		}).on('cancel.daterangepicker', function(event, picker){
			var $this = $(this),
				startDateId = options.startDateId || $this.data('startDateId'),
				endDateId = options.endDateId || $this.data('endDateId');
			
			$this.val('');
			
			if(startDateId){
				$(startDateId).val('');
			}
			
			if(endDateId){
				$(endDateId).val('');
			}
		});
		
		return picker;
	};
	
	/**
	 * @param  el        html元素、jquery对象、jquery的selector
	 * @param  options   select2的参数
	 */
	SpdUI.select2 = function(el, options){
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		if(options === null || options === undefined || !$.isPlainObject(options)){
			options = {};
		}
		
		options = $.extend({
			minimumResultsForSearch: Infinity
		}, options);
		
		$el.select2(options);
	};
	
	/**
	 * @param  el        html元素、jquery对象、jquery的selector
	 * @param  options   Bootstrap Table的参数
	 */
	SpdUI.bootstrapTable = function(el, options){
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		if(options === null || options === undefined || !$.isPlainObject(options)){
			options = {};
		}
		
		options = $.extend({
			pagination: true,
			smartDisplay: true,
	        pageSize: 20,
	        pageList: [10, 20, 30, 50, 75, 100],
	        sidePagination: 'server',
	        showRefresh: false,
	        showColumns: false,
	        cache: false
		}, options);
		
		var columns = options.columns;
		if(!$.isArray(columns) || columns.length === 0){
			return;
		}
		
		$.each(columns, function(i, v){
			v.spdFormatter = v.formatter;
			v.formatter = function(value, row, index) {
				var col = this, text = value;
				
				if($.isFunction(v.spdFormatter)){
					text = v.spdFormatter.call(col, value, row, index);
				}
				
				if(col.overflow === 'hidden') {
					var width = $el.find('thead>tr>th[data-field="' + col.field + '"]').width() - 20;
					text = '<div style="margin:0;padding:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;-o-text-overflow:ellipsis;width:' + width + 'px;">' + text + '</div>';
				}
				
				return text;
			};
			
			columns[i] = $.extend({
				align: 'center',
				valign: 'middle'
			}, v);
		});
		
		if(!$.isFunction(options.responseHandler)){
			options.responseHandler = function(responseData){
				return SpdUI.isResultSuccess(responseData) ? responseData.data : [];
			};
		}
		
		$el.bootstrapTable(options);
	};
	
	/**
	 * 
	 */
	SpdUI.buildTreeNodes = function(rows, options) {
		/*
		 options = {
		 	fieldId: 'id',
		 	fieldParentId: 'parentId',
		 	compare: function(a, b){
		 	}
		 }
		 
		 node = {
		 	id: 1,
		 	parentId: 0,
		 	name: '名称',
		 	hasParent: false,
		 	hasChildren: false,
		 	nodeData: {},
		 	children: []
		 }
		 */
		
		var nodes = [];
		
		if(!$.isArray(rows) || rows.length === 0){
			return nodes;
		}
		
		if(!$.isPlainObject(options)){
			options = {};
		}
		
		options = $.extend({
			fieldId: 'id',
		 	fieldParentId: 'parentId',
		 	fieldName: 'name',
		}, options);
		
		if(!$.isFunction(options.compare)){
			options.compare = null;
		}
		
		$.each(rows, function(i, v){
			nodes.push({
				id: v[options.fieldId],
				parentId: v[options.fieldParentId],
				name: v[options.fieldName],
				nodeData: v
			});
		});
		
		$.each(nodes, function(i, parent){
			$.each(nodes, function(j, child){
				if(child.parentId == parent.id){
					if(!$.isArray(parent.children)){
						parent.children = [];
					}
					child.hasParent = true;
					parent.hasChildren = true;
					parent.children.push(child);
				}
			});
		});
		
		var tops = [], compare = options.compare;
		$.each(nodes, function(i, node){
			if($.isArray(node.children)){
				node.children.sort(compare);
			}
			
			if(!node.hasParent){
				tops.push(node);
			}
		});
		
		if(compare){
			tops.sort(compare);
		}
		
		return tops;
	};
	
	SpdUI.buildTreeTableRows = function(nodes, columns, $table){
		var fnbuild = function(nodes, columns){
			var html = [];
			if(!$.isArray(nodes) || nodes.length === 0){
				return html;
			}
			
			$.each(nodes, function(i, node){
				var row = node.nodeData;
				var tr = '<tr data-tt-id="' + row.id + '" data-tt-parent-id="' + row.parentId + '" data-node-data="' + SpdUI.encodeBase64(JSON.stringify(row)) + '">';
				
				$.each(columns, function(j, col){
					var align = col.align || 'center',
						valign = col.valign || 'middle',
						field = col.field,
						formatter = col.formatter,
						cssClass = col.cssClass || '',
						style = col.style || '',
						treeColumnCls = '',
						value = null;
					
					if(col.tree === true){
						align = 'left';
						treeColumnCls = 'spd-tree-column';
					}
					
					var td = '<td class="' + cssClass + ' ' + treeColumnCls + '" data-field="' + field + '" style="text-align:' + align + ';vertical-align:' + valign + ';' + style + '">';

					if(col.tree === true){
						td += '<span class="text">';
					}else{
						if(col.hideOverflow === true){
							td += '<div class="spd-column-hide-overflow" style="' + ($table.find('th[data-field="' + field + '"]').width() - 20) + 'px;">';							
						}else{
							td += '<div>';
						}
					}
					
					if(SpdUI.isString(field)){
						field = $.trim(field);
						if(field !== ''){
							value = row[field];
						}
					}
					
					if($.isFunction(formatter)){
						value = formatter(value, row, i);
					}
					
					td += value;
					
					td += (col.tree === true) ? '</span>' : '</div>';					
					td += '</td>';
					
					tr += td;
				});
				
				tr += '</tr>';
				
				html.push(tr);
				
				if(node.hasChildren){
					html = html.concat(fnbuild(node.children, columns));
				}
			});
			
			return html;
		};
		
		return fnbuild(nodes, columns).join('');
	};
	
	SpdUI.getTreeTableSelected = function(el) {
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		var $trs = $el.find('tr.selected');
		if($trs.length === 0){
			return;
		}
		
		return $el.treetable('node', $trs.data('ttId'));
	};
	
	SpdUI.getTreeTableSelectedNodeData = function(el) {
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		var $trs = $el.find('tr.selected');
		if($trs.length === 0){
			return;
		}
		
		return $.parseJSON(SpdUI.decodeBase64($trs.data('nodeData')));
	};
	
	SpdUI.addTreeTableNode = function(el, parentId, nodeData) {
		SpdUI.addTreeTableNodes(el, parentId, [nodeData]);
	};
	
	SpdUI.addTreeTableNodes = function(el, parentId, nodeDatas) {
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		var parentNode = null;
		if(parentId !== null && parentId !== undefined && parentId !== ''){
			parentNode = $el.treetable('node', parentId);
		}
		
		var options = $el.data('spdTreeTableOptions'),
			htmlRows = SpdUI.buildTreeTableRows(SpdUI.buildTreeNodes(nodeDatas), options.columns, $el);
		
		$el.treetable('loadBranch', parentNode, htmlRows);
	};
	
	/**
	 * @param  el        html元素、jquery对象、jquery的selector
	 * @param  options   jstreegird的参数
	 */
	SpdUI.treetable = function(el, options){
		if(el === null || el === undefined){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		$el.addClass('spd-treetable table table-hover table-bordered');
		
		if(options === null || options === undefined || !$.isPlainObject(options) || !$.isArray(options.columns) || options.columns.length === 0){
			return;
		}
		
		/*
		options = {
			expandAll: false,
			columns: [{
				tree: false,
				width: 100,
				title: '性别',
				field: '',
				style: '',
				cssClass: '',
				hideOverflow: false,
				formatter: function(value, row, index){}
			}],
			dataType: 'json' //json,ajax,
			url: '',
			data: []
		}
		*/
		
		options = $.extend({
			expandAll: false,
			dataType: 'json',
			data: []
		}, options);
		
		$el.data('spdTreeTableOptions', options);
		
		var headers = [],
			treeColumn = 0,
			treeopts = {
				expandable: true,
				expanderTemplate: '<i class="fa fa-caret-right"></i>',
				onInitialized: function() {
					var tree = this, options = $(tree.table).data('spdTreeTableOptions');
					if(options.expandAll === true){
						setTimeout(function() {
							tree.expandAll();
						}, 100);
					}
					
					if($.isFunction(options.onInitialized)){
						options.onInitialized.apply(tree);
					}
				}
			};
		
		$.each(options.columns, function(i, v){
			var width = '',
				align = v.align || 'center',
				valign = v.valign || 'middle',
				treeColumnCls = '';
			
			if($.isNumeric(v.width)){
				width = 'width:' + (+v.width) + 'px;';
			}if(SpdUI.isString(v.width) && v.width !== ''){
				width = 'width:' + v.width + ';';
			}
			
			if(v.tree === true){
				treeColumn = i;
				//align = 'left';
				treeColumnCls = 'spd-tree-column';
			}
			
			headers.push('<th class="' + treeColumnCls + '" data-field="' + v.field + '" style="text-align:' + align + ';vertical-align:' + valign + ';' + width + '">' + v.title + '</th>');
		});
		
		treeopts.column = treeColumn;
		
		$el.html('<thead><tr>' + headers.join('') + '</tr></thead><tbody><tr><td colspan="' + headers.length + '">&nbsp;</td></tr></tbody>');
		
		var columns = options.columns;
		if(options.dataType === 'json'){
			$el.children('tbody').html(SpdUI.buildTreeTableRows(SpdUI.buildTreeNodes(options.data), columns, $el));
			$el.treetable(treeopts);
		}else if(options.dataType === 'ajax'){
			SpdUI.getJSON({
				url: options.url,
				failure: false,
				success: function(data, json){
					var nodes = SpdUI.buildTreeNodes(data, function(a, b){
						return a.sort - b.sort;
					});
					
					$el.children('tbody').html(SpdUI.buildTreeTableRows(nodes, columns, $el));
					$el.treetable(treeopts);
				}
			});
		}
		
		$el.children('tbody').on('mousedown', 'tr', function(){
			var $this = $(this);
			$this.parent().children('.selected').removeClass("selected");
			$this.addClass("selected");
		});
		
		$el.children('tbody').on('dblclick', 'tr', function(){
			var $this = $(this);
			if($this.hasClass('expanded')){
				$this.closest('.spd-treetable').treetable('collapseNode', +$this.data('ttId'));
			}else{
				$this.closest('.spd-treetable').treetable('expandNode', +$this.data('ttId'));
			}
		});
	};
	
	SpdUI.addTab = function(options){
		/*
		options = {
			id: 'id',
            title: 'title',
            url: 'url'
		};
		*/
		
		window.top.Addtabs.add(options);
	};
	
	SpdUI.closeTab = function(id){
		var Addtabs = window.top.Addtabs;
		Addtabs.close('tab_' + id);
		Addtabs.drop();
	};
	
	SpdUI.refreshTab = function(id){
		window.top.Addtabs.add({
			id: id,
			title: window.top.$('tab_tab_' + id).children('a').html(),
			url: window.top.$('tab_tab_' + id).attr('aria-url')
		});
	};
	
	
	/**
	 * ajax请求
	 * 参数 options = {
	 *         url: '',
	 *         data: '',
	 *         success: function(data, json){},
	 *         failure: function(json, message){},
	 *         dataType: 'json',
	 *         type: 'get'
	 *     }
	 */
	SpdUI.ajax = function(options) {
		if(!$.isPlainObject(options)){
			return;
		}
		
		var success = options.success,
			failure = options.failure,
			ajaxopts = {
				url: options.url,
				dataType: options.dataType || 'json',
				type: options.type || 'get'
			};
		
		if(options.data){
			ajaxopts.data = options.data;
		}
		
		if(failure !== false && !$.isFunction(failure)){
			failure = function(json, message){
				SpdUI.alert(message || '操作失败');
			}
		}
		
		return $.ajax(ajaxopts).done(function(json){
			if(SpdUI.isResultSuccess(json)){
				$.isFunction(success) && success(json.data, json);
			}else{
				if($.isFunction(failure)){
					if(json && json.message){
						failure(json, json.message);
					}else{
						failure(json);
					}
				}
			}
		}).fail(function(){
			if($.isFunction(failure)){
				failure();
			}
		});
	};
	
	SpdUI.getJSON = function(options) {
		if(!$.isPlainObject(options)){
			return;
		}
		
		options.type = 'get';
		options.dataType = 'json';
		
		SpdUI.ajax(options);
	};
	
	SpdUI.postJSON = function(options) {
		if(!$.isPlainObject(options)){
			return;
		}
		
		options.type = 'post';
		options.dataType = 'json';
		
		SpdUI.ajax(options);
	};
	
	/**
	 * 表单提交ajax请求
	 * @param form 表单元素、id、jQuery对象
	 * @param options 参数
	 * options = {
	 *  	url: '',
     *      data: '',
     *      success: function(data, json){},
     *  	failure: function(json, message){},
     *		beforeSubmit: function($form, formData){},
     *  	validate: false
	 * }
	 */
	SpdUI.ajaxSubmit = function(form, options){
		if(form === null || form === undefined || !$.isPlainObject(options)){
			return;
		}
		
		var $form = $(form);
		if($form.length === 0){
			return;
		}
		
		var tmpfn = function($form, options){
			// 执行之前
			if($.isFunction(options.beforeSubmit) && options.beforeSubmit($form, SpdUI.formToObject($form)) === false){
				return;
			}
			
			var fnSuccess = options.success,
				fnFailure = options.failure;
				
			if(fnSuccess !== false && !$.isFunction(fnSuccess)){
				fnSuccess = function(data, json){
					SpdUI.alert(json.message || '操作成功');
				}
			}
				
			if(fnFailure !== false && !$.isFunction(fnFailure)){
				fnFailure = function(json, message){
					SpdUI.alert(message || '操作失败');
				}
			}
				
			var ajaxopts = {
				url: options.url,
				dataType: 'json',
				type: 'post',
				success: function(json){
					if(SpdUI.isResultSuccess(json)){
						$.isFunction(fnSuccess) && fnSuccess(json.data, json);
					}else{
						if($.isFunction(fnFailure)){
							if(json && json.message){
								fnFailure(json, json.message);
							}else{
								fnFailure(json);
							}
						}
					}
				},
				failure: function(){
					if($.isFunction(fnFailure)){
						fnFailure();
					}
				}
			};
				
			if(options.data){
				ajaxopts.data = options.data;
			}
			
			$form.ajaxSubmit(ajaxopts);
		};
		
		//是否需要校验
		if(options.validate === true){
			SpdUI.isValid($form, function(){
				tmpfn($form, options);
			});
		}else{
			tmpfn($form, options);
		}
	}
	
	SpdUI.getImageUploaderList = function(el) {
		var files = [];
		
		if(el === null || el === undefined){
			return files;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return files;
		}		
		
		$el.find('.spd-upload-item').each(function(){
			var $this = $(this);
			
			if($this.hasClass('spd-upload-item-default')){
				return;
			}
			
			files.push({
				file: $this.data('file'),
				uploadResult: $this.data('uploadResult'),
				url: $this.find('img').data('url')
			});
		});
		
		return files;
	};
	
	SpdUI.addToImageUploader = function(el, urls) {
		if(el === null || el === undefined || !$.isArray(urls) || urls.length === 0){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		$el.addClass('spd-upload-wrapper clearfix');
		
		var $list = $el.children('.spd-upload-list');
		if($list.length === 0) {
			return;
		}
		
		$list.find('.spd-upload-item-default').remove();
		
		var spdopts = $el.data('spdopts');
		
		$.each(urls, function(i, url){
			var html = [
				'<div class="spd-upload-item spd-upload-item-default">',
					'<div class="spd-upload-image-wrapper">',
						'<img src="' + url + '">',
						'<div class="spd-upload-progress progress">',
							'<div class="progress-bar progress-bar-warning" style="width:0;">0%</div>',
						'</div>',
						'<div class="spd-upload-error">',
							'<div>上传失败</div>',
							'<div class="spd-upload-refresh"><i class="fa fa-refresh fa-3x fa-fw"></i></div>',
						'</div>',
					'</div>',							
				'</div>'
			].join('');
			
			var $item = $(html);
			if(spdopts.imageTools === true) {
				$item.append([
					'<div class="spd-item-tools">',
						'<div class="btn btn-default btn-xs spd-item-tool-pre">前移</div>',
						'<div class="btn btn-default btn-xs spd-item-tool-next">后移</div>',
						'<div class="btn btn-default btn-xs spd-item-tool-del">删除</div>',
					'</div>'
				].join(''));
			}
			
			$item.find('img').data('url', url);
			$list.append($item);
		});
	};
	
	SpdUI.resetImageUploader = function($el) {
		var uploader = $el.data('spdUploader'),
			options = $el.data('spdOptions'),
			spdopts = $el.data('spdopts');
		
		uploader.reset();
		
		$el.find('.spd-upload-item').each(function(){
			$(this).remove();
		});
		
		$el.children('.spd-upload-list').html('');
		
		if(spdopts.defaultImageCount > 0) {
			(function(){
				for(var i = 0; i < spdopts.defaultImageCount; i++){
					var html = [
						'<div class="spd-upload-item spd-upload-item-default">',
							'<div class="spd-upload-image-wrapper">',
								'<img src="' + spdopts.defaultImageUrl + '">',
								'<div class="spd-upload-progress progress">',
									'<div class="progress-bar progress-bar-warning" style="width:0;">0%</div>',
								'</div>',
								'<div class="spd-upload-error">',
									'<div>上传失败</div>',
									'<div class="spd-upload-refresh"><i class="fa fa-refresh fa-3x fa-fw"></i></div>',
								'</div>',
							'</div>',							
						'</div>'
					].join('');
					
					var $item = $(html);
					if(spdopts.imageTools === true) {
						$item.append([
							'<div class="spd-item-tools">',
								'<div class="btn btn-default btn-xs spd-item-tool-pre">前移</div>&nbsp;',
								'<div class="btn btn-default btn-xs spd-item-tool-next">后移</div>&nbsp;',
								'<div class="btn btn-default btn-xs spd-item-tool-del">删除</div>',
							'</div>'
						].join(''));
					}
					
					$el.children('.spd-upload-list').append($item);
				}
			})();
		}
	};
	
	SpdUI.imageUploader = function(el, spdopts) {
		if(el === null || el === undefined || !$.isPlainObject(spdopts)){
			return;
		}
		
		var $el = $(el);
		if($el.length === 0){
			return;
		}
		
		$el.addClass('spd-upload-wrapper clearfix');
		
		/*
		defaultImageUrl: '',
		defaultImageCount: 1,
		maxImageCount: 1,
		uploadMessage: '',
		imageTools: true,
		uploadSuccess: function(json, file, uploader, $el){},
		server: ''
		*/
		
		spdopts = $.extend({
			defaultImageUrl: '',
			defaultImageCount: 0,
			imageTools: true,
			uploadMessage: '',
			uploadLabel: '选择文件'
		}, spdopts);
		
		$el.append([
			'<div class="spd-upload-toolbar">',
				'<div class="spd-upload-picker">' + spdopts.uploadLabel + '</div>',				
			'</div>',
			'<div class="spd-upload-msg">' + spdopts.uploadMessage + '</div>',
			'<div class="spd-upload-list clearfix">',
			'</div>'
		].join(''));
		
		var options = $.extend({
			auto: true,
			swf: SpdUI.contextPath + '/static/lib/webuploader/Uploader.swf',
		    pick: $el.find('.spd-upload-picker'),
		    accept: {
		        title: 'Images',
		        extensions: 'gif,jpg,jpeg,bmp,png',
		        mimeTypes: 'image/*'
		    },
		    fileVal: 'uploadfile',
		    thumb: {
		    	width: 120,
		        height: 120,

		        // 图片质量，只有type为`image/jpeg`的时候才有效。
		        quality: 70,

		        // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.
		        allowMagnify: true,

		        // 是否允许裁剪。
		        crop: true

		        // 为空的话则保留原有图片格式。
		        // 否则强制转换成指定的类型。
		        //type: 'image/jpeg'
		    }
		}, {
			server: spdopts.server
		});
		
		if(spdopts.defaultImageCount > 0) {
			(function(){
				for(var i = 0; i < spdopts.defaultImageCount; i++){
					var html = [
						'<div class="spd-upload-item spd-upload-item-default">',
							'<div class="spd-upload-image-wrapper">',
								'<img src="' + spdopts.defaultImageUrl + '">',
								'<div class="spd-upload-progress progress">',
									'<div class="progress-bar progress-bar-warning" style="width:0;">0%</div>',
								'</div>',
								'<div class="spd-upload-error">',
									'<div>上传失败</div>',
									'<div class="spd-upload-refresh"><i class="fa fa-refresh fa-3x fa-fw"></i></div>',
								'</div>',
							'</div>',							
						'</div>'
					].join('');
					
					var $item = $(html);
					if(spdopts.imageTools === true) {
						$item.append([
							'<div class="spd-item-tools">',
								'<div class="btn btn-default btn-xs spd-item-tool-pre">前移</div>&nbsp;',
								'<div class="btn btn-default btn-xs spd-item-tool-next">后移</div>&nbsp;',
								'<div class="btn btn-default btn-xs spd-item-tool-del">删除</div>',
							'</div>'
						].join(''));
					}
					
					$el.children('.spd-upload-list').append($item);
				}
			})();
		}
		
		var uploader = WebUploader.create(options);
		
		$el.data('spdUploader', uploader);
		$el.data('spdOptions', options);
		$el.data('spdopts', spdopts);
		
		$el.on('click', '.spd-item-tool-prev', function(){
			var $item = $(this).closest('.spd-upload-item'),
				$prev = $item.prev();
			
			if($item.length !== 0 && $prev.length !== 0) {
				$prev.insertAfter($item);
			}
			
			return false;
		});
		
		$el.on('click', '.spd-item-tool-next', function(){
			var $item = $(this).closest('.spd-upload-item'),
				$next = $item.next();
			
			if($item.length !== 0 && $next.length !== 0) {
				$next.insertBefore($item);
			}
			
			return false;
		});
		
		$el.on('click', '.spd-item-tool-del', function(){
			var file = $(this).closest('.spd-upload-item').data('file');
			if(file){
				$el.data('spdUploader').removeFile(file);
			}
			
			$(this).closest('.spd-upload-item').remove();
			
			return false;
		});
		
		$el.on('click', '.spd-upload-refresh', function(){
			var $item = $(this).closest('.spd-upload-item');
			
			$el.data('spdUploader').retry($item.data('file'));
			
			$item.find('.spd-upload-progress').show();
			$item.find('.spd-upload-error').hide();
			
			var $progress = $item.find('.progress-bar');
		    $progress.css('width', '0');
		    $progress.html('0%');
						
			return false;
		});
		
		uploader.on('fileQueued', function(file) {
			var $item = $el.find('.spd-upload-item-default').first();
			if($item.length !== 0){
				$item.remove();
			}
			
			var html = [
				'<div class="spd-upload-item" data-file-id="' + file.id + '">',
					'<div class="spd-upload-image-wrapper">',
						'<img >',
						'<div class="spd-upload-progress progress">',
							'<div class="progress-bar progress-bar-warning" style="width:0;">0%</div>',
						'</div>',
						'<div class="spd-upload-error">',
							'<div>上传失败</div>',
							'<div class="spd-upload-refresh"><i class="fa fa-refresh fa-3x fa-fw"></i></div>',
						'</div>',
					'</div>',
				'</div>'
			].join('');
			
			$item = $(html);
			if(spdopts.imageTools === true) {
				$item.append([
					'<div class="spd-item-tools">',
						'<div class="btn btn-default btn-xs spd-item-tool-prev">前移</div>&nbsp;',
						'<div class="btn btn-default btn-xs spd-item-tool-next">后移</div>&nbsp;',
						'<div class="btn btn-default btn-xs spd-item-tool-del">删除</div>',
					'</div>'
				].join(''));
			}
			
			$el.children('.spd-upload-list').append($item);
			
			$item.data('file', file);
			
			if(spdopts.maxImageCount && $el.find('.spd-upload-item').length > spdopts.maxImageCount){
				var prevFile = $item.prev().data('file');
				if(prevFile){
					uploader.removeFile(prevFile);
				}
				
				$item.prev().remove();
			}

		    // 创建缩略图
		    // 如果为非图片文件，可以不用调用此方法。
		    uploader.makeThumb(file, function( error, src ) {
		        if(error){
		        	$item.find('img').attr('src', options.defaultImage);
		        	return;
		        }

		        $item.find('img').attr('src', src);
		    }, options.thumb.width, options.thumb.height);
		});
		
		uploader.on('uploadProgress', function(file, percentage){
		    var $bar = $el.find('.spd-upload-item[data-file-id="' + file.id + '"]>.spd-upload-progress'),
		    	$progress = $bar.find('.progress-bar');
		    
		    $bar.show();
		    $progress.css('width', percentage * 100 + '%');
		    $progress.html('' + percentage + '%');
		});

		// 文件上传成功，给item添加成功class, 用样式标记上传成功。
		uploader.on( 'uploadSuccess', function(file, json){
			var $item = $el.find('.spd-upload-item[data-file-id="' + file.id + '"]'),
				spdopts = $el.data('spdopts');
			
			$item.children('.spd-upload-progress').hide();
			
			$item.data('uploadResult', json);
			if(SpdUI.isResultSuccess(json)){				
				$item.find('img').data('url', json.data.url);
			}else{
				$item.find('img').data('url', '');
				$item.find('.spd-upload-progress').hide();
				$item.find('.spd-upload-error').show();
			}
			
			if($.isFunction(spdopts.uploadSuccess)){
				spdopts.uploadSuccess(json, file, $el.data('spdUploader'), $el);
			}
		});

		// 文件上传失败，显示上传出错。
		uploader.on('uploadError', function(file){
			$el.find('.spd-upload-item[data-file-id="' + file.id + '"]>.spd-upload-progress').hide();
			$el.find('.spd-upload-item[data-file-id="' + file.id + '"]>.spd-upload-error').show();
		});
		
		uploader.on('uploadComplete', function(file){
			$el.find('.spd-upload-item[data-file-id="' + file.id + '"]>.spd-upload-progress').hide();
		});
	};
});